import { IMode } from "./IMode";
import { ArmatureController } from "../ArmatureController";
import { Rotate as RotateBar } from "../../views/OperatorBar/Rotate";
import { Point } from "pixi.js";
import { emitter } from "../../../eventEmitter";
import { Transform as MyTransform } from "../../geom/Transform";
import { ItransformableItem } from "../ITransformableItem";

type CursorState = {
    state: "selectedEmpty" | "inSelected" | "inUnSelected" | "inSpace";
    target: ItransformableItem | null;
};

export class RotateController implements IMode {
    private _ctrl: ArmatureController;
    private _preDragMovePoint = new Point();
    private _curDragMovePoint = new Point();
    public operateBar: RotateBar;
    private _cursorState: CursorState = { state: "selectedEmpty", target: null };

    constructor(ctrl: ArmatureController) {
        this._ctrl = ctrl;
        this.operateBar = new RotateBar();
        this._ctrl.view.addChild(this.operateBar);
        this.operateBar.visible = false;
    }

    private _rotateItem(item: ItransformableItem, pre: Point, cur: Point) {
        let parent = item.parent;
        let position = item.view.position;
        if (parent) {
            pre = parent.view.toLocal(pre);
            cur = parent.view.toLocal(cur);
            position = parent.view.toLocal(position);
        }

        let rotationTo = Math.atan2((cur.y - position.y), (cur.x - position.x));
        let rotationFrom = Math.atan2((pre.y - position.y), (pre.x - position.x));
        let rotation = rotationTo - rotationFrom;
        item.transform.rotation += rotation;
        item.updateMatrixByLocalTransform();
        item.updateSubItems();
    }

    private _rotateAction(): void {
        let armatureCtrl = this._ctrl;

        //只操作最高节点
        let items = armatureCtrl.selectedItemManager.getMinItems();
        if (items) {
            for (const item of items) {
                this._rotateItem(item, this._preDragMovePoint, this._curDragMovePoint);
            }
        }
        this._preDragMovePoint.copyFrom(this._curDragMovePoint);
        this.updateOperateBar(true);
    }

    public onDragMove(event: any): void {
        this._curDragMovePoint.set(event.global.x, event.global.y);
        this._rotateAction();
    }

    public onDragMoveEnd(event: any): void {

    }

    private _clickHandler() {
        let armatureCtrl = this._ctrl;

        switch (this._cursorState.state) {
            case "inUnSelected":
                if (this._cursorState.target) {
                    armatureCtrl.selectedItemManager.clearSelectedItems();
                    armatureCtrl.selectedItemManager.addSelectItem(this._cursorState.target);
                }

                break;

            default:
                break;
        }
    }

    public onDragStart(event: any): void {
        let point = new Point(event.global.x, event.global.y);
        this.updateCursorState(point);

        //let armatureCtrl = this._ctrl;
        this._preDragMovePoint.set(event.global.x, event.global.y);
        this._clickHandler();
        this.updateCursorState(point);

        this.updateOperateBar(true);
    }

    public getCursorState(position: Point): CursorState {
        const armatureCtrl = this._ctrl;
        let ret: CursorState = {
            state: "selectedEmpty",
            target: null,
        };

        for (const bone of armatureCtrl.boneControllers) {
            if (bone.isContainPoint(position)) {
                if (armatureCtrl.selectedItemManager.selectedItemsSet.has(bone)) {
                    ret.state = "inSelected";
                    ret.target = bone;
                    return ret;
                } else {
                    ret.state = "inUnSelected";
                    ret.target = bone;
                    return ret;
                }
            }
        }

        let displayList = armatureCtrl.getCurDisplayList();
        if (displayList) {
            for (const display of displayList) {
                if (display.isContainPoint(position)) {
                    if (armatureCtrl.selectedItemManager.selectedItemsSet.has(display)) {
                        ret.state = "inSelected";
                        ret.target = display;
                        return ret;
                    } else {
                        ret.state = "inUnSelected";
                        ret.target = display;
                        return ret;
                    }
                }
            }
        }

        if (armatureCtrl.selectedItemManager.selectedItemsSet.size > 0) {
            ret.state = "inSpace";
        }
        return ret;
    }

    public updateCursorState(position: Point): void {
        const cursorState = this.getCursorState(position);
        if (this._cursorState.state !== cursorState.state || this._cursorState.target !== cursorState.target) {
            this._cursorState.state = cursorState.state;
            this._cursorState.target = cursorState.target;
        }
    }

    private _hoverHandler() {
        let armatureCtrl = this._ctrl;
        let bone = this._cursorState.target;
        if (bone) {
            if (armatureCtrl.hoverItem == null || armatureCtrl.hoverItem !== bone) {
                bone.hoverEnter();
                if (armatureCtrl.hoverItem) {
                    armatureCtrl.hoverItem.hoverLeave();
                }
                armatureCtrl.hoverItem = bone;
            }
        } else {
            if (armatureCtrl.hoverItem) {
                armatureCtrl.hoverItem.hoverLeave();
                armatureCtrl.hoverItem = null;
            }
        }
    }

    public onHover(event: any): void {
        let point = new Point(event.global.x, event.global.y);
        this.updateCursorState(point);
        this._hoverHandler();
    }

    public onEnter(): void {
        this.updateOperateBar(true);
        emitter.emit("changeCursor", "rotate");
    }

    public onLeave(): void {
        this.updateOperateBar(false);
    }

    public updateOperateBar(visible: boolean): void {
        let armatureCtrl = this._ctrl;

        if (visible) {
            let operateBone = armatureCtrl.selectedItemManager.getOperateItem();
            console.log("operate bar", operateBone);
            if (operateBone) {
                this.operateBar.visible = true;
                if (operateBone.view.rotation != 0) {
                    this.operateBar.setTransform(operateBone.view.position.x, operateBone.view.position.y, 1, 1, operateBone.view.rotation);
                } else {
                    let rotation = MyTransform.normalizeRadian(operateBone.view.skew.y);
                    this.operateBar.setTransform(operateBone.view.position.x, operateBone.view.position.y, 1, 1, rotation);
                }
                console.log("rotate rotate", operateBone.view.rotation, operateBone.view.skew.x, operateBone.view.skew.y);
                this.operateBar.target = operateBone;
            }
        } else {
            this.operateBar.target = null;
            this.operateBar.visible = false;
        }
    }
}